package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.LoginMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ReportMapper;
import com.sky.mapper.WorkspaceMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.asm.Advice;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.BinaryOperator;

@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    private LoginMapper loginMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private WorkspaceService workspaceService;


    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = getDates(begin, end);

        ArrayList<Double> turnoverList = new ArrayList<>();
        Map map = new HashMap();


        dateList.forEach(date -> {
            map.put("status", Orders.COMPLETED);
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Double turnover = orderMapper.turnoverStatistics(map);
            turnover = turnover == null ? 0.0 : turnover;
            turnoverList.add(turnover);
        });

        return TurnoverReportVO.builder().dateList(StringUtils.join(dateList, ",")).turnoverList(StringUtils.join(turnoverList, ",")).build();
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = getDates(begin, end);

        List<Integer> newUserList = new ArrayList<>();
        List<Integer> totalUserList = new ArrayList<>();
        Map map = new HashMap();
        dateList.forEach(date -> {
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer newUser = loginMapper.userStatistics(map);
            newUserList.add(newUser);

            map.put("beginTime", null);
            Integer totalUser = loginMapper.userStatistics(map);
            totalUserList.add(totalUser);
        });


        return UserReportVO.builder().dateList(StringUtils.join(dateList)).newUserList(StringUtils.join(newUserList, ",")).totalUserList(StringUtils.join(totalUserList, ",")).build();
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = getDates(begin, end);

        List<Integer> totalOrderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        Integer totalOrderCount = 0;
        Integer validOrderCount = 0;
        Double orderCompletionRate = 0.0;
        Map map = new HashMap();

        for (LocalDate date : dateList) {
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer totalOrder = orderMapper.countByMap(map);
            totalOrderCountList.add(totalOrder);

            map.put("status", Orders.COMPLETED);
            Integer orderCount = orderMapper.countByMap(map);
            validOrderCountList.add(orderCount);

        }

        totalOrderCount = totalOrderCountList.stream().reduce(Integer::sum).get();
        validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();

        if (totalOrderCount != 0) {
            orderCompletionRate = (double) validOrderCount / totalOrderCount;
        }


        return OrderReportVO.builder().dateList(StringUtils.join(dateList, ",")).orderCompletionRate(orderCompletionRate).orderCountList(StringUtils.join(validOrderCountList, ",")).validOrderCount(validOrderCount).totalOrderCount(totalOrderCount).validOrderCountList(StringUtils.join(validOrderCountList, ",")).build();
    }

    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        Map map = new HashMap();
        ArrayList<String> nameList = new ArrayList<>();
        ArrayList<Integer> numberList = new ArrayList<>();
        map.put("beginTime", LocalDateTime.of(begin, LocalTime.MIN));
        map.put("endTime", LocalDateTime.of(end, LocalTime.MAX));
        map.put("status", Orders.COMPLETED);
        List<GoodsSalesDTO> list = orderMapper.top10(map);

        System.out.println("list = " + list);

        for (GoodsSalesDTO salesDTO : list) {
            String name = salesDTO.getName();
            Integer number = salesDTO.getNumber();
            nameList.add(name);
            numberList.add(number);
        }
        return SalesTop10ReportVO.builder().nameList(StringUtils.join(nameList, ",")).numberList(StringUtils.join(numberList, ",")).build();
    }

    @Override
    public void export(HttpServletResponse httpServletResponse) throws IOException {
        LocalDate beginDate = LocalDate.now().minusDays(30);
        LocalDate endDate = LocalDate.now().minusDays(1);
        BusinessDataVO businessDataVO = workspaceService.businessData(LocalDateTime.of(beginDate, LocalTime.MIN), LocalDateTime.of(endDate, LocalTime.MAX));

        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");

        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream);

        XSSFSheet sheetAt = xssfWorkbook.getSheetAt(0);
        sheetAt.getRow(1).getCell(1).setCellValue(beginDate +"至" + endDate);

        XSSFRow row = sheetAt.getRow(3);
        row.getCell(2).setCellValue(businessDataVO.getTurnover());
        row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
        row.getCell(6).setCellValue(businessDataVO.getNewUsers());

        row = sheetAt.getRow(4);
        row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());
        row.getCell(4).setCellValue(businessDataVO.getUnitPrice());

        for (int i = 0; i < 30; i++) {
            LocalDate date = beginDate.plusDays(i);
            businessDataVO = workspaceService.businessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(endDate, LocalTime.MAX));
            row = sheetAt.getRow(7 + i);
            row.getCell(1).setCellValue(date.toString());
            row.getCell(2).setCellValue(businessDataVO.getTurnover());
            row.getCell(3).setCellValue(businessDataVO.getValidOrderCount());
            row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
            row.getCell(5).setCellValue(businessDataVO.getUnitPrice());
            row.getCell(6).setCellValue(businessDataVO.getNewUsers());
        }

        ServletOutputStream outputStream = httpServletResponse.getOutputStream();

        xssfWorkbook.write(outputStream);

        outputStream.flush();
        outputStream.close();
        xssfWorkbook.close();


    }

    private static List<LocalDate> getDates(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        while (!begin.isAfter(end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        return dateList;
    }
}
